/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.registry.integration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.Version;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.registry.NotifyListener;
import com.alibaba.dubbo.registry.Registry;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Protocol;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcInvocation;
import com.alibaba.dubbo.rpc.cluster.Cluster;
import com.alibaba.dubbo.rpc.cluster.Configurator;
import com.alibaba.dubbo.rpc.cluster.ConfiguratorFactory;
import com.alibaba.dubbo.rpc.cluster.Router;
import com.alibaba.dubbo.rpc.cluster.RouterFactory;
import com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory;
import com.alibaba.dubbo.rpc.cluster.directory.StaticDirectory;
import com.alibaba.dubbo.rpc.cluster.support.ClusterUtils;
import com.alibaba.dubbo.rpc.protocol.InvokerWrapper;
import com.alibaba.dubbo.rpc.support.RpcUtils;

/**
 * RegistryDirectory
 * 
 * @author william.liangf
 * @author chao.liuc
 */
public class RegistryDirectory<T> extends AbstractDirectory<T> implements
		NotifyListener {

	private static final Logger logger = LoggerFactory
			.getLogger(RegistryDirectory.class);

	private static final Cluster cluster = ExtensionLoader.getExtensionLoader(
			Cluster.class).getAdaptiveExtension();

	private static final RouterFactory routerFactory = ExtensionLoader
			.getExtensionLoader(RouterFactory.class).getAdaptiveExtension();

	private static final ConfiguratorFactory configuratorFactory = ExtensionLoader
			.getExtensionLoader(ConfiguratorFactory.class)
			.getAdaptiveExtension();

	private Protocol protocol; // 注入时初始化，断言不为null

	private Registry registry; // 注入时初始化，断言不为null

	private final String serviceKey; // 构造时初始化，断言不为null

	private final Class<T> serviceType; // 构造时初始化，断言不为null

	private final Map<String, String> queryMap; // 构造时初始化，断言不为null

	private final URL directoryUrl; // 构造时初始化，断言不为null，并且总是赋非null值

	private final String[] serviceMethods;

	private final String serviceEids;

	private final boolean multiGroup;

	private volatile boolean forbidden = false;

	private volatile URL overrideDirectoryUrl; // 构造时初始化，断言不为null，并且总是赋非null值

	/*
	 * override规则 优先级：override>-D>consumer>provider 第一种规则：针对某个provider
	 * <ip:port,timeout=100> 第二种规则：针对所有provider <* ,timeout=5000>
	 */
	private volatile List<Configurator> configurators; // 初始为null以及中途可能被赋为null，请使用局部变量引用

	// Map<url, Invoker> cache service url to invoker mapping.
	private volatile Map<String, Invoker<T>> urlInvokerMap; // 初始为null以及中途可能被赋为null，请使用局部变量引用

	// Map<methodName, Invoker> cache service method to invokers mapping.
	// private volatile Map<String, List<Invoker<T>>> methodInvokerMap; //
	// 初始为null以及中途可能被赋为null，请使用局部变量引用

	private volatile Map<String, Map<String, List<Invoker<T>>>> methodInvokerMap;// Eid
	// Set<invokerUrls> cache invokeUrls to invokers mapping.
	private volatile Set<URL> cachedInvokerUrls; // 初始为null以及中途可能被赋为null，请使用局部变量引用

	public RegistryDirectory(Class<T> serviceType, URL url) {
		super(url);
		if (serviceType == null)
			throw new IllegalArgumentException("service type is null.");
		if (url.getServiceKey() == null || url.getServiceKey().length() == 0)
			throw new IllegalArgumentException("registry serviceKey is null.");
		this.serviceType = serviceType;
		this.serviceKey = url.getServiceKey();
		this.queryMap = StringUtils.parseQueryString(url
				.getParameterAndDecoded(Constants.REFER_KEY));
		this.overrideDirectoryUrl = this.directoryUrl = url
				.setPath(url.getServiceInterface()).clearParameters()
				.addParameters(queryMap).removeParameter(Constants.MONITOR_KEY);
		String group = directoryUrl.getParameter(Constants.GROUP_KEY, "");
		this.multiGroup = group != null
				&& ("*".equals(group) || group.contains(","));
		String methods = queryMap.get(Constants.METHODS_KEY);
		this.serviceMethods = methods == null ? null
				: Constants.COMMA_SPLIT_PATTERN.split(methods);
		this.serviceEids = url.getParameter(Constants.GENERIC_EID);
	}

	public void setProtocol(Protocol protocol) {
		this.protocol = protocol;
	}

	public void setRegistry(Registry registry) {
		this.registry = registry;
	}

	public void subscribe(URL url) {
		setConsumerUrl(url);
		registry.subscribe(url, this);
	}

	public void destroy() {
		if (isDestroyed()) {
			return;
		}
		// unsubscribe.
		try {
			if (getConsumerUrl() != null && registry != null
					&& registry.isAvailable()) {
				registry.unsubscribe(getConsumerUrl(), this);
			}
		} catch (Throwable t) {
			logger.warn("unexpeced error when unsubscribe service "
					+ serviceKey + "from registry" + registry.getUrl(), t);
		}
		super.destroy(); // 必须在unsubscribe之后执行
		try {
			destroyAllInvokers();
		} catch (Throwable t) {
			logger.warn("Failed to destroy service " + serviceKey, t);
		}
	}

	public synchronized void notify(List<URL> urls) {
		List<URL> invokerUrls = new ArrayList<URL>();
		List<URL> routerUrls = new ArrayList<URL>();
		List<URL> configuratorUrls = new ArrayList<URL>();
		for (URL url : urls) {
			String protocol = url.getProtocol();
			String category = url.getParameter(Constants.CATEGORY_KEY,
					Constants.DEFAULT_CATEGORY);
			if (Constants.ROUTERS_CATEGORY.equals(category)
					|| Constants.ROUTE_PROTOCOL.equals(protocol)) {
				routerUrls.add(url);
			} else if (Constants.CONFIGURATORS_CATEGORY.equals(category)
					|| Constants.OVERRIDE_PROTOCOL.equals(protocol)) {
				configuratorUrls.add(url);
			} else if (Constants.PROVIDERS_CATEGORY.equals(category)) {
				invokerUrls.add(url);
			} else {
				logger.warn("Unsupported category " + category
						+ " in notified url: " + url + " from registry "
						+ getUrl().getAddress() + " to consumer "
						+ NetUtils.getLocalHost());
			}
		}
		// configurators
		if (configuratorUrls != null && configuratorUrls.size() > 0) {
			this.configurators = toConfigurators(configuratorUrls);
		}
		// routers
		if (routerUrls != null && routerUrls.size() > 0) {
			List<Router> routers = toRouters(routerUrls);
			if (routers != null) { // null - do nothing
				setRouters(routers);
			}
		}
		List<Configurator> localConfigurators = this.configurators; // local
																	// reference
		// 合并override参数
		this.overrideDirectoryUrl = directoryUrl;
		if (localConfigurators != null && localConfigurators.size() > 0) {
			for (Configurator configurator : localConfigurators) {
				this.overrideDirectoryUrl = configurator
						.configure(overrideDirectoryUrl);
			}
		}
		// providers
		refreshInvoker(invokerUrls);
	}

	/**
	 * 根据invokerURL列表转换为invoker列表。转换规则如下：
	 * 1.如果url已经被转换为invoker，则不在重新引用，直接从缓存中获取，注意如果url中任何一个参数变更也会重新引用
	 * 2.如果传入的invoker列表不为空，则表示最新的invoker列表
	 * 3.如果传入的invokerUrl列表是空，则表示只是下发的override规则或route规则，需要重新交叉对比，决定是否需要重新引用。
	 * 
	 * @param invokerUrls
	 *            传入的参数不能为null
	 */
	private void refreshInvoker(List<URL> invokerUrls) {
		if (invokerUrls != null
				&& invokerUrls.size() == 1
				&& invokerUrls.get(0) != null
				&& Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0)
						.getProtocol())) {
			this.forbidden = true; // 禁止访问
			this.methodInvokerMap = null; // 置空列表

			destroyAllInvokers(); // 关闭所有Invoker
		} else {
			this.forbidden = false; // 允许访问
			Map<String, Invoker<T>> oldUrlInvokerMap = this.urlInvokerMap; // local
																			// reference
			if (invokerUrls.size() == 0 && this.cachedInvokerUrls != null) {
				invokerUrls.addAll(this.cachedInvokerUrls);
			} else {
				this.cachedInvokerUrls = new HashSet<URL>();
				this.cachedInvokerUrls.addAll(invokerUrls);// 缓存invokerUrls列表，便于交叉对比
			}
			if (invokerUrls.size() == 0) {
				return;
			}
			Map<String, Invoker<T>> newUrlInvokerMap = toInvokers(invokerUrls);// 将URL列表转成Invoker列表
			Map<String, Map<String, List<Invoker<T>>>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap); // 换方法名映射Invoker列表
			// state change
			// 如果计算错误，则不进行处理.
			if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0) {
				logger.error(new IllegalStateException(
						"urls to invokers error .invokerUrls.size :"
								+ invokerUrls.size()
								+ ", invoker.size :0. urls :"
								+ invokerUrls.toString()));
				return;
			}
			this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap)
					: newMethodInvokerMap;
			this.urlInvokerMap = newUrlInvokerMap;
			try {
				destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // 关闭未使用的Invoker
			} catch (Exception e) {
				logger.warn("destroyUnusedInvokers error. ", e);
			}
		}
	}

	private Map<String, Map<String, List<Invoker<T>>>> toMergeMethodInvokerMap(
			Map<String, Map<String, List<Invoker<T>>>> MethodMap) {
		Map<String, Map<String, List<Invoker<T>>>> result = new HashMap<String, Map<String, List<Invoker<T>>>>();
		for (Map.Entry<String, Map<String, List<Invoker<T>>>> entry : MethodMap
				.entrySet()) {
			String method = entry.getKey();
			Map<String, List<Invoker<T>>> eidinvokers = entry.getValue();
			Map<String, Map<String, List<Invoker<T>>>> groupMap = new HashMap<String, Map<String, List<Invoker<T>>>>();
			for (Map.Entry<String, List<Invoker<T>>> eidEntry : eidinvokers
					.entrySet()) {
				String eid = eidEntry.getKey();
				List<Invoker<T>> invokers = eidEntry.getValue();
				Map<String, List<Invoker<T>>> groupInvokers = new HashMap<String, List<Invoker<T>>>();
				for (Invoker<T> invoker : invokers) {
					String group = invoker.getUrl().getParameter(
							Constants.GROUP_KEY, "");
					groupInvokers = groupMap.get(group);
					if (groupInvokers == null) {
						groupInvokers = new HashMap<String, List<Invoker<T>>>();
						groupMap.put(group, groupInvokers);
					}
				}
				groupInvokers.put(eid, invokers);
			}
			if (groupMap.size() == 1) {
				result.put(method, groupMap.values().iterator().next());
			} else if (groupMap.size() > 1) {
				Map<String, List<Invoker<T>>> groupInvokers = new HashMap<String, List<Invoker<T>>>();
				List<Invoker<T>> groupList = new ArrayList<Invoker<T>>();
				for (Map<String, List<Invoker<T>>> groupMap2 : groupMap
						.values()) {
					for (Map.Entry<String, List<Invoker<T>>> eidGroupEntry : groupMap2
							.entrySet()) {
						String eid = eidGroupEntry.getKey();
						List<Invoker<T>> invokers = eidGroupEntry.getValue();
						groupList.add(cluster.join(new StaticDirectory<T>(
								invokers)));
						groupInvokers.put(eid, groupList);
					}
				}
				result.put(method, groupInvokers);
			} else {
				result.put(method, eidinvokers);
			}
		}

		return result;

	}

	/**
	 * 将overrideURL转换为map，供重新refer时使用. 每次下发全部规则，全部重新组装计算
	 * 
	 * @param urls
	 *            契约： </br>
	 *            1.override://0.0.0.0/...(或override://ip:port...?anyhost=true)&
	 *            para1=value1...表示全局规则(对所有的提供者全部生效) </br>
	 *            2.override://ip:port...?anyhost=false 特例规则（只针对某个提供者生效） </br>
	 *            3.不支持override://规则... 需要注册中心自行计算. </br>
	 *            4.不带参数的override://0.0.0.0/ 表示清除override
	 * @return
	 */
	public static List<Configurator> toConfigurators(List<URL> urls) {
		List<Configurator> configurators = new ArrayList<Configurator>(
				urls.size());
		if (urls == null || urls.size() == 0) {
			return configurators;
		}
		for (URL url : urls) {
			if (Constants.EMPTY_PROTOCOL.equals(url.getProtocol())) {
				configurators.clear();
				break;
			}
			Map<String, String> override = new HashMap<String, String>(
					url.getParameters());
			// override 上的anyhost可能是自动添加的，不能影响改变url判断
			override.remove(Constants.ANYHOST_KEY);
			if (override.size() == 0) {
				configurators.clear();
				continue;
			}
			configurators.add(configuratorFactory.getConfigurator(url));
		}
		Collections.sort(configurators);
		return configurators;
	}

	/**
	 * 
	 * @param urls
	 * @return null : no routers ,do nothing else :routers list
	 */
	private List<Router> toRouters(List<URL> urls) {
		List<Router> routers = new ArrayList<Router>();
		if (urls == null || urls.size() < 1) {
			return routers;
		}
		if (urls != null && urls.size() > 0) {
			for (URL url : urls) {
				if (Constants.EMPTY_PROTOCOL.equals(url.getProtocol())) {
					continue;
				}
				String routerType = url.getParameter(Constants.ROUTER_KEY);
				if (routerType != null && routerType.length() > 0) {
					url = url.setProtocol(routerType);
				}
				try {
					Router router = routerFactory.getRouter(url);
					if (!routers.contains(router))
						routers.add(router);
				} catch (Throwable t) {
					logger.error("convert router url to router error, url: "
							+ url, t);
				}
			}
		}
		return routers;
	}

	/**
	 * 将urls转成invokers,如果url已经被refer过，不再重新引用。
	 * 
	 * @param urls
	 * @param overrides
	 * @param query
	 * @return invokers
	 */
	private Map<String, Invoker<T>> toInvokers(List<URL> urls) {
		Map<String, Invoker<T>> newUrlInvokerMap = new HashMap<String, Invoker<T>>();
		if (urls == null || urls.size() == 0) {
			return newUrlInvokerMap;
		}
		Set<String> keys = new HashSet<String>();
		String queryProtocols = this.queryMap.get(Constants.PROTOCOL_KEY);
		for (URL providerUrl : urls) {
			// 如果reference端配置了protocol，则只选择匹配的protocol
			if (queryProtocols != null && queryProtocols.length() > 0) {
				boolean accept = false;
				String[] acceptProtocols = queryProtocols.split(",");
				for (String acceptProtocol : acceptProtocols) {
					if (providerUrl.getProtocol().equals(acceptProtocol)) {
						accept = true;
						break;
					}
				}
				if (!accept) {
					continue;
				}
			}
			if (Constants.EMPTY_PROTOCOL.equals(providerUrl.getProtocol())) {
				continue;
			}
			if (!ExtensionLoader.getExtensionLoader(Protocol.class)
					.hasExtension(providerUrl.getProtocol())) {
				logger.error(new IllegalStateException("Unsupported protocol "
						+ providerUrl.getProtocol()
						+ " in notified url: "
						+ providerUrl
						+ " from registry "
						+ getUrl().getAddress()
						+ " to consumer "
						+ NetUtils.getLocalHost()
						+ ", supported protocol: "
						+ ExtensionLoader.getExtensionLoader(Protocol.class)
								.getSupportedExtensions()));
				continue;
			}
			URL url = mergeUrl(providerUrl);

			String key = url.toFullString(); // URL参数是排序的
			if (keys.contains(key)) { // 重复URL
				continue;
			}
			keys.add(key);
			// 缓存key为没有合并消费端参数的URL，不管消费端如何合并参数，如果服务端URL发生变化，则重新refer
			Map<String, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local
																				// reference
			Invoker<T> invoker = localUrlInvokerMap == null ? null
					: localUrlInvokerMap.get(key);
			if (invoker == null) { // 缓存中没有，重新refer
				try {
					boolean enabled = true;
					if (url.hasParameter(Constants.DISABLED_KEY)) {
						enabled = !url.getParameter(Constants.DISABLED_KEY,
								false);
					} else {
						enabled = url.getParameter(Constants.ENABLED_KEY, true);
					}
					if (enabled) {
						invoker = new InvokerDelegete<T>(protocol.refer(
								serviceType, url), url, providerUrl);
					}
				} catch (Throwable t) {
					logger.error(
							"Failed to refer invoker for interface:"
									+ serviceType + ",url:(" + url + ")"
									+ t.getMessage(), t);
				}
				if (invoker != null) { // 将新的引用放入缓存
					newUrlInvokerMap.put(key, invoker);
				}
			} else {
				newUrlInvokerMap.put(key, invoker);
			}
		}
		keys.clear();
		return newUrlInvokerMap;
	}

	/**
	 * 合并url参数 顺序为override > -D >Consumer > Provider
	 * 
	 * @param providerUrl
	 * @param overrides
	 * @return
	 */
	private URL mergeUrl(URL providerUrl) {
		providerUrl = ClusterUtils.mergeUrl(providerUrl, queryMap); // 合并消费端参数

		List<Configurator> localConfigurators = this.configurators; // local
																	// reference
		if (localConfigurators != null && localConfigurators.size() > 0) {
			for (Configurator configurator : localConfigurators) {
				providerUrl = configurator.configure(providerUrl);
			}
		}

		providerUrl = providerUrl.addParameter(Constants.CHECK_KEY,
				String.valueOf(false)); // 不检查连接是否成功，总是创建Invoker！

		// directoryUrl 与 override 合并是在notify的最后，这里不能够处理
		this.overrideDirectoryUrl = this.overrideDirectoryUrl
				.addParametersIfAbsent(providerUrl.getParameters()); // 合并提供者参数

		if ((providerUrl.getPath() == null || providerUrl.getPath().length() == 0)
				&& "dubbo".equals(providerUrl.getProtocol())) { // 兼容1.0
			// fix by tony.chenl DUBBO-44
			String path = directoryUrl.getParameter(Constants.INTERFACE_KEY);
			if (path != null) {
				int i = path.indexOf('/');
				if (i >= 0) {
					path = path.substring(i + 1);
				}
				i = path.lastIndexOf(':');
				if (i >= 0) {
					path = path.substring(0, i);
				}
				providerUrl = providerUrl.setPath(path);
			}
		}
		return providerUrl;
	}

	private List<Invoker<T>> route(List<Invoker<T>> invokers, String method) {
		Invocation invocation = new RpcInvocation(method, new Class<?>[0],
				new Object[0]);
		List<Router> routers = getRouters();
		if (routers != null) {
			for (Router router : routers) {
				if (router.getUrl() != null
						&& !router.getUrl().getParameter(Constants.RUNTIME_KEY,
								true)) {
					invokers = router.route(invokers, getConsumerUrl(),
							invocation);
				}
			}
		}
		return invokers;
	}

	/**
	 * 将invokers列表转成与方法的映射关系 方法映射成eid关系表
	 * 
	 * @param invokersMap
	 *            Invoker列表
	 * @return Invoker与方法的映射关系
	 */

	private Map<String, Map<String, List<Invoker<T>>>> toMethodInvokers(
			Map<String, Invoker<T>> invokersMap) {

//		Map<String, List<Invoker<T>>> newEidInvokerMap = new HashMap<String, List<Invoker<T>>>();
		Map<String, Map<String, List<Invoker<T>>>> newMethodInvokerMap = new HashMap<String, Map<String, List<Invoker<T>>>>();
		// 按提供者URL所声明的methods分类，兼容注册中心执行路由过滤掉的methods
		Map<String, List<Invoker<T>>> eidInvokerMap = new HashMap<String, List<Invoker<T>>>();
		if (invokersMap != null && invokersMap.size() > 0) {
			for (Invoker<T> invoker : invokersMap.values()) {
				List<Invoker<T>> invokersList = new ArrayList<Invoker<T>>();
				String parameter = invoker.getUrl().getParameter(
						Constants.METHODS_KEY);
				String parameterEid = invoker.getUrl().getParameter(
						Constants.GENERIC_EID);
				parameterEid = parameterEid == null ? Constants.DEFAULT_EID
						: parameterEid;
				if (parameter != null && parameter.length() > 0) {
					String[] methods = Constants.COMMA_SPLIT_PATTERN
							.split(parameter);
					if (methods != null && methods.length > 0) {
						for (String method : methods) {
							if (method != null && method.length() > 0
									&& !Constants.ANY_VALUE.equals(method)) {
								Map<String, List<Invoker<T>>> methodInvokers = newMethodInvokerMap
										.get(method);
								if (methodInvokers == null) {
									methodInvokers = new HashMap<String, List<Invoker<T>>>();
									newMethodInvokerMap.put(method,
											methodInvokers);
								}

								if (parameterEid != null
										&& parameterEid.length() > 0
										&& !Constants.ANY_VALUE
												.equals(parameterEid)) {
									List<Invoker<T>> eidInvokers = methodInvokers
											.get(parameterEid);
									if (eidInvokers == null) {
										eidInvokers = new ArrayList<Invoker<T>>();
										methodInvokers.put(parameterEid,
												eidInvokers);
									}
									eidInvokers.add(invoker);
								}

							}
						}
					}
				}
				invokersList = eidInvokerMap.get(parameterEid);
				if (invokersList == null) {
					invokersList = new ArrayList<Invoker<T>>();
				}
				invokersList.add(invoker);
				eidInvokerMap.put(parameterEid, invokersList);
			}
		}
		newMethodInvokerMap.put(Constants.ANY_VALUE, eidInvokerMap);
		// if (serviceEids != null) {
		// List<Invoker<T>> eidInvokers = newEidInvokerMap.get(serviceEids);
		// if (eidInvokers == null || eidInvokers.size() == 0) {
		// eidInvokers = invokersList;
		// }
		// newEidInvokerMap.put(serviceEids, route(eidInvokers, serviceEids));
		// }
		if (serviceMethods != null && serviceMethods.length > 0) {
			for (String method : serviceMethods) {
				Map<String, List<Invoker<T>>> methodInvokers = newMethodInvokerMap
						.get(method);
				List<Invoker<T>> eidInvokers = methodInvokers
						.get(serviceEids);
				if (methodInvokers == null || methodInvokers.size() == 0) {
					methodInvokers = eidInvokerMap;
				}
				methodInvokers.put(serviceEids, route(eidInvokers, serviceEids));
				newMethodInvokerMap.put(method, methodInvokers);
			}
		}
		// sort and unmodifiable
		// for (String method : new
		// HashSet<String>(newMethodInvokerMap.keySet())) {
		// List<Invoker<T>> methodInvokers = newMethodInvokerMap.get(method);
		// Collections.sort(methodInvokers, InvokerComparator.getComparator());
		// newMethodInvokerMap.put(method,
		// Collections.unmodifiableList(methodInvokers));
		// }
		// sort and unmodifiable
		for (String method : new HashSet<String>(newMethodInvokerMap.keySet())) {
			Map<String, List<Invoker<T>>> methodInvokers = newMethodInvokerMap
					.get(method);
			for (String eid : new HashSet<String>(methodInvokers.keySet())) {
				List<Invoker<T>> eidInvokers = methodInvokers.get(eid);
				Collections
						.sort(eidInvokers, InvokerComparator.getComparator());
				methodInvokers.put(eid,
						Collections.unmodifiableList(eidInvokers));
			}
			newMethodInvokerMap.put(method,
					Collections.unmodifiableMap(methodInvokers));
		}
		return Collections.unmodifiableMap(newMethodInvokerMap);
	}

	/**
	 * 关闭所有Invoker
	 */
	private void destroyAllInvokers() {
		Map<String, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local
																			// reference
		if (localUrlInvokerMap != null) {
			for (Invoker<T> invoker : new ArrayList<Invoker<T>>(
					localUrlInvokerMap.values())) {
				try {
					invoker.destroy();
				} catch (Throwable t) {
					logger.warn("Failed to destroy service " + serviceKey
							+ " to provider " + invoker.getUrl(), t);
				}
			}
			localUrlInvokerMap.clear();
		}
		methodInvokerMap = null;
	}

	/**
	 * 检查缓存中的invoker是否需要被destroy
	 * 如果url中指定refer.autodestroy=false，则只增加不减少，可能会有refer泄漏，
	 * 
	 * @param invokers
	 */

	private void destroyUnusedInvokers(
			Map<String, Invoker<T>> oldUrlInvokerMap,
			Map<String, Invoker<T>> newUrlInvokerMap) {
		if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0) {
			destroyAllInvokers();
			return;
		}
		// check deleted invoker
		List<String> deleted = null;
		if (oldUrlInvokerMap != null) {
			Collection<Invoker<T>> newInvokers = newUrlInvokerMap.values();
			for (Map.Entry<String, Invoker<T>> entry : oldUrlInvokerMap
					.entrySet()) {
				if (!newInvokers.contains(entry.getValue())) {
					if (deleted == null) {
						deleted = new ArrayList<String>();
					}
					deleted.add(entry.getKey());
				}
			}
		}

		if (deleted != null) {
			for (String url : deleted) {
				if (url != null) {
					Invoker<T> invoker = oldUrlInvokerMap.remove(url);
					if (invoker != null) {
						try {
							invoker.destroy();
							if (logger.isDebugEnabled()) {
								logger.debug("destory invoker["
										+ invoker.getUrl() + "] success. ");
							}
						} catch (Exception e) {
							logger.warn("destory invoker[" + invoker.getUrl()
									+ "] faild. " + e.getMessage(), e);
						}
					}
				}
			}
		}
	}

	/**
	 * 原代码
	 */
	public List<Invoker<T>> doList(Invocation invocation) {
		if (forbidden) {
			throw new RpcException(
					RpcException.FORBIDDEN_EXCEPTION,
					"Forbid consumer "
							+ NetUtils.getLocalHost()
							+ " access service "
							+ getInterface().getName()
							+ " from registry "
							+ getUrl().getAddress()
							+ " use dubbo version "
							+ Version.getVersion()
							+ ", Please check registry access list (whitelist/blacklist).");
		}

		List<Invoker<T>> invokers = null;
		Map<String, Map<String, List<Invoker<T>>>> localMethodInvokerMap = this.methodInvokerMap; // local
																									// reference
		if (localMethodInvokerMap != null && localMethodInvokerMap.size() > 0) {
			String methodName = RpcUtils.getMethodName(invocation);
			String eid = invocation.getAttachment(Constants.GENERIC_EID);
			String ePath = registry.getAnyEid(eid);
			String[] eids = ePath == null ? new String[] { eid } : ePath
					.split("/");
			Map<String, List<Invoker<T>>> invokersMap = null;
			Object[] args = RpcUtils.getArguments(invocation);
			if (args != null
					&& args.length > 0
					&& args[0] != null
					&& (args[0] instanceof String || args[0].getClass()
							.isEnum())) {
				invokersMap = localMethodInvokerMap.get(methodName + "."
						+ args[0]);
			}
			if (invokersMap == null) {
				invokersMap = localMethodInvokerMap.get(methodName);
			}
			if (invokersMap == null) {
				invokersMap = localMethodInvokerMap.get(Constants.ANY_VALUE);
			}
			if (invokersMap == null) {
				Iterator<Map<String, List<Invoker<T>>>> iterator = localMethodInvokerMap
						.values().iterator();
				if (iterator.hasNext()) {
					invokersMap = iterator.next();
				}
			}
			invokers = filter(invokersMap, eids);
		}
		return invokers == null ? new ArrayList<Invoker<T>>(0) : invokers;
	}

	private List<Invoker<T>> filter(Map<String, List<Invoker<T>>> invokersMap,
			String[] eidArray) {
		int i = 0;
		for (i = eidArray.length - 1; i >= 0; i--) {
			String eid = eidArray[i];
			if (invokersMap.containsKey(eid)) {
				return invokersMap.get(eid);
			}
		}
		return null;
	}

	public Class<T> getInterface() {
		return serviceType;
	}

	public URL getUrl() {
		return this.overrideDirectoryUrl;
	}

	public boolean isAvailable() {
		if (isDestroyed()) {
			return false;
		}
		Map<String, Invoker<T>> localUrlInvokerMap = urlInvokerMap;
		if (localUrlInvokerMap != null && localUrlInvokerMap.size() > 0) {
			for (Invoker<T> invoker : new ArrayList<Invoker<T>>(
					localUrlInvokerMap.values())) {
				if (invoker.isAvailable()) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Haomin: added for test purpose
	 */
	public Map<String, Invoker<T>> getUrlInvokerMap() {
		return urlInvokerMap;
	}

	/**
	 * Haomin: added for test purpose
	 */
	public Map<String, Map<String, List<Invoker<T>>>> getMethodInvokerMap() {
		return methodInvokerMap;
	}

	private static class InvokerComparator implements Comparator<Invoker<?>> {

		private static final InvokerComparator comparator = new InvokerComparator();

		public static InvokerComparator getComparator() {
			return comparator;
		}

		private InvokerComparator() {
		}

		public int compare(Invoker<?> o1, Invoker<?> o2) {
			return o1.getUrl().toString().compareTo(o2.getUrl().toString());
		}

	}

	/**
	 * 代理类，主要用于存储注册中心下发的url地址，用于重新重新refer时能够根据providerURL queryMap
	 * overrideMap重新组装
	 * 
	 * @author chao.liuc
	 * @param <T>
	 */
	private static class InvokerDelegete<T> extends InvokerWrapper<T> {
		private URL providerUrl;

		public InvokerDelegete(Invoker<T> invoker, URL url, URL providerUrl) {
			super(invoker, url);
			this.providerUrl = providerUrl;
		}

		public URL getProviderUrl() {
			return providerUrl;
		}
	}
}